﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Phone.BackgroundTransfer;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.BackgroundAudio;
using Microsoft.Phone.Shell;
using GlobalClass;

namespace VK
{
    public partial class Audio : PhoneApplicationPage
    {
        bool settingSliderFromPlay;
        private IsolatedStorageFile fileStorage;
        private string _albumId;
        BitmapImage _btRepeat, _btShuffle;

        private const String URI_LOCATION = "https://api.vk.com/method/";
        private const String SAVE_LOCATION = "shared/transfers/";
        private readonly Uri _songsDownloadUri = new Uri(URI_LOCATION + "audio.get.xml?access_token=" + App._accessToken);
        private readonly Uri _albumsDownloadUri = new Uri(URI_LOCATION + "audio.getAlbums.xml?access_token=" + App._accessToken);
        private readonly Uri _songsSaveLocationUri = new Uri(SAVE_LOCATION + "allSongsList.xml", UriKind.RelativeOrAbsolute);
        private readonly Uri _albumsSaveLocationUri = new Uri(SAVE_LOCATION + "albumsList.xml", UriKind.RelativeOrAbsolute);
        private BackgroundTransferRequest _songsDownloadRequest, _albumsDownloadRequest;

        public Audio()
        {
            InitializeComponent();
            
            _btRepeat = new BitmapImage();
            _btShuffle = new BitmapImage();
            fileStorage = IsolatedStorageFile.GetUserStoreForApplication();
            // Set fields of appbar buttons; otherwise they're null
            prevAppBarButton = this.ApplicationBar.Buttons[0] as ApplicationBarIconButton;
            playAppBarButton = this.ApplicationBar.Buttons[1] as ApplicationBarIconButton;
            pauseAppBarButton = this.ApplicationBar.Buttons[2] as ApplicationBarIconButton;
            nextAppBarButton = this.ApplicationBar.Buttons[3] as ApplicationBarIconButton;

            BackgroundAudioPlayer.Instance.PlayStateChanged += Instance_PlayStateChanged;
            CompositionTarget.Rendering += OnCompositionTargetRendering;
            
            DownloadXmlSongsList();
            SetRightIcons();
        }

        #region APP BAR BUTTONS

        private void prevButton_Click(object sender, EventArgs eventArgs)
        {
            BackgroundAudioPlayer.Instance.SkipPrevious();
            prevAppBarButton.IsEnabled = false;
        }

        private void playButton_Click(object sender, EventArgs eventArgs)
        {
            BackgroundAudioPlayer.Instance.Play();
            playAppBarButton.IsEnabled = false;
        }

        private void pauseButton_Click(object sender, EventArgs eventArgs)
        {
            BackgroundAudioPlayer.Instance.Pause();
            pauseAppBarButton.IsEnabled = false;
        }

        private void nextButton_Click(object sender, EventArgs eventArgs)
        {
            BackgroundAudioPlayer.Instance.SkipNext();
            nextAppBarButton.IsEnabled = false;
        }

        #endregion APP BAR BUTTONS

        void Instance_PlayStateChanged(object sender, EventArgs e)
        {
            UpdateScreen();
        }

        void OnCompositionTargetRendering(object sender, EventArgs args)
        {
            AudioTrack audioTrack = null;
            TimeSpan position = TimeSpan.Zero;
            TimeSpan duration = TimeSpan.Zero;

            try
            {
                // Sometimes these property accesses will raise exceptions
                audioTrack = BackgroundAudioPlayer.Instance.Track;

                if (audioTrack != null)
                {
                    duration = audioTrack.Duration;
                    position = BackgroundAudioPlayer.Instance.Position;
                }
            }
            catch
            {
            }

            if (audioTrack != null)
            {
                elapsedDuration.Text = position.ToString("m\\:ss");
                totalDuration.Text = duration.ToString("m\\:ss");

                // Change the Slider position, but set a flag to 
                //  avoid the ValueChanged handler from being confused.
                settingSliderFromPlay = true;

                if (duration.Ticks > 0)
                    positionSlider.Value = (double)position.Ticks / duration.Ticks;
                else
                    positionSlider.Value = 0;

                settingSliderFromPlay = false;
            }
            else
            {
                elapsedDuration.Text = null;
                totalDuration.Text = null;
                positionSlider.Value = 0;
            }
        }

        void OnSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> args)
        {
            if (!settingSliderFromPlay)
            {
                AudioTrack audioTrack = null;
                TimeSpan duration = TimeSpan.Zero;

                try
                {
                    // Sometimes these property accesses will raise exceptions
                    audioTrack = BackgroundAudioPlayer.Instance.Track;

                    if (audioTrack != null)
                        duration = audioTrack.Duration;
                }
                catch
                {
                }

                if (audioTrack == null)
                    return;

                long ticks = (long)(args.NewValue * duration.Ticks);
                BackgroundAudioPlayer.Instance.Position = new TimeSpan(ticks);
            }
        }

        void UpdateScreen()
        {
            PlayState state = PlayState.Unknown;
            AudioTrack audioTrack = null;

            try
            {
                // Sometimes these property accesses will raise exceptions
                state = BackgroundAudioPlayer.Instance.PlayerState;
                audioTrack = BackgroundAudioPlayer.Instance.Track;
            }
            catch
            {
            }

            
            
            playerState.Text = state != PlayState.Unknown ? state.ToString() : null;

            /*if (state == PlayState.Playing)
            {
                BitmapImage bi3 = new BitmapImage();
                bi3.UriSource = new Uri(audioTrack.AlbumArt.AbsoluteUri, UriKind.Absolute);
                Cover.Stretch = Stretch.None;
                Cover.Source = bi3;
                Cover.Visibility = Visibility.Visible;
            }
            else
            {
                Cover.Visibility = Visibility.Collapsed;
            }*/

            if (audioTrack != null)
            {
                albumText.Text = audioTrack.Album;
                artistText.Text = audioTrack.Artist;
                trackText.Text = audioTrack.Title;

                positionSlider.Visibility = Visibility.Visible;
                repeatImg.Visibility = Visibility.Visible;
                shuffleImg.Visibility = Visibility.Visible;
                emptyDefaultText.Visibility = Visibility.Collapsed;

                prevAppBarButton.IsEnabled = 0 != (audioTrack.PlayerControls & EnabledPlayerControls.SkipPrevious);
                nextAppBarButton.IsEnabled = 0 != (audioTrack.PlayerControls & EnabledPlayerControls.SkipNext);
                playAppBarButton.IsEnabled = BackgroundAudioPlayer.Instance.PlayerState == PlayState.Paused;
                pauseAppBarButton.IsEnabled = BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing;                

                /*if (AudioFilesList.Items.Any())
                {
                    AudioFilesList.SelectedIndex = AudioFilesList.Items.IndexOf(audioTrack.Title + " - " + audioTrack.Artist);
                }*/
            }
            else
            {
                albumText.Text = null;
                artistText.Text = null;
                trackText.Text = null;

                positionSlider.Visibility = Visibility.Collapsed;

                prevAppBarButton.IsEnabled = false;
                playAppBarButton.IsEnabled = true;
                pauseAppBarButton.IsEnabled = false;
                nextAppBarButton.IsEnabled = false;
            }
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            UpdateScreen();
            base.OnNavigatedTo(e);

            IDictionary<string, string> parameters = this.NavigationContext.QueryString;
            if (parameters.ContainsKey("access_token")) App._accessToken = parameters["access_token"];
        }

        private void GetAudioFilesFromAlbum()
        {
            var c = new WebClient();
            c.OpenReadCompleted += c_OpenAudioFilesReadCompleted;
            string getAudioFiles = "https://api.vk.com/method/audio.get.xml?album_id=" + _albumId + "&access_token=" + App._accessToken;
            c.OpenReadAsync(new Uri(getAudioFiles));
        }

        void c_OpenAudioFilesReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            // изменяем текущий плейлист, сохраняя туда песни из альбома
            XDocument audioFilesFromAlbum = XDocument.Load(e.Result);
            using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/playList.xml", FileMode.Create))
            {
                StreamWriter writer = new StreamWriter(isostream);
                writer.Write(audioFilesFromAlbum);
                writer.Close();
            }
            // изменяем отображение текущего плейлиста
            var audioElements = audioFilesFromAlbum.Root.Elements();
            AudioFilesList.Items.Clear();
            foreach (var audioElement in audioElements)
            {
                if (audioElement.HasElements)
                {
                    AudioFilesList.Items.Add(audioElement.Element("artist").Value + " - " + audioElement.Element("title").Value);
                }
            }
        }

        private void DownloadXmlSongsList()
        {
            DeleteExistsFilesAndRequests();

            _songsDownloadRequest = new BackgroundTransferRequest(_songsDownloadUri, _songsSaveLocationUri);
            _songsDownloadRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;

            _albumsDownloadRequest = new BackgroundTransferRequest(_albumsDownloadUri, _albumsSaveLocationUri);
            _albumsDownloadRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;

            BackgroundTransferService.Add(_albumsDownloadRequest);
            BackgroundTransferService.Add(_songsDownloadRequest);

            _songsDownloadRequest.TransferStatusChanged += ViewSongsOnAudioPage;
        }

        private void ViewSongsOnAudioPage(object sender, BackgroundTransferEventArgs e)
        {
            progressBar1.Visibility = Visibility.Collapsed;
            playAppBarButton.IsEnabled = true;
            // add line "all songs" before
            AlbumsList.Items.Add("Все песни");
            if (Convert.ToBoolean(_albumsDownloadRequest.TransferStatus) && !Convert.ToBoolean(_albumsDownloadRequest.TransferError))
            {
                using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/albumsList.xml", FileMode.Open))
                {
                    XDocument albumsList = XDocument.Load(isostream);
                    var albumsElements = albumsList.Root.Elements();
                    foreach (var albumElement in albumsElements)
                    {
                        if (albumElement.HasElements)
                        {
                            AlbumsList.Items.Add(albumElement.Element("title").Value);
                        }
                    }
                }
            }
            if (Convert.ToBoolean(_songsDownloadRequest.TransferStatus) && !Convert.ToBoolean(_songsDownloadRequest.TransferError))
            {
                fileStorage.CopyFile("shared/transfers/allSongsList.xml", "shared/transfers/playList.xml", true);
                using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/playList.xml", FileMode.Open))
                {
                    XDocument songsList = XDocument.Load(isostream);
                    var audioElements = songsList.Root.Elements();
                    foreach (var audioElement in audioElements)
                    {
                        AudioFilesList.Items.Add(audioElement.Element("artist").Value + " - " + audioElement.Element("title").Value);
                    }
                }
            }
            
        }

        #region DELETE METHODS

        private void DeleteExistsFilesAndRequests()
        {
            foreach (var bacgroundRequest in BackgroundTransferService.Requests)
            {
                RemoveTransferRequest(bacgroundRequest.RequestId);
            }
            using (IsolatedStorageFile userStore = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (userStore.FileExists(SAVE_LOCATION))
                {
                    userStore.DeleteFile(SAVE_LOCATION);
                }
                /*if (userStore.FileExists("currentTrackNumber.txt"))
                {
                    userStore.DeleteFile("currentTrackNumber.txt");
                }*/
            }
        }

        private void RemoveTransferRequest(string transferID)
        {
            // Use Find to retrieve the transfer request with the specified ID.
            BackgroundTransferRequest transferToRemove = BackgroundTransferService.Find(transferID);

            // Try to remove the transfer from the background transfer service.
            try
            {
                BackgroundTransferService.Remove(transferToRemove);
            }
            catch
            {
                // Handle the exception.
            }
        }

        #endregion DELETE METHODS

        #region SELECTION CHANGED METHODS

        private void AlbumsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems[0].ToString() == "Все песни")
            {
                fileStorage.CopyFile("shared/transfers/allSongsList.xml", "shared/transfers/playList.xml", true);
                AudioFilesList.Items.Clear();
                using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/playList.xml", FileMode.Open))
                {
                    XDocument songsList = XDocument.Load(isostream);
                    var audioElements = songsList.Root.Elements();
                    foreach (var audioElement in audioElements)
                    {
                        AudioFilesList.Items.Add(audioElement.Element("artist").Value + " - " + audioElement.Element("title").Value);
                    }
                }
            }
            else if (fileStorage.FileExists("shared/transfers/albumsList.xml"))
            {
                using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/albumsList.xml", FileMode.Open))
                {
                    XDocument albumsList = XDocument.Load(isostream);
                    var albumsElements = albumsList.Root.Elements();
                    foreach (var albumElement in albumsElements)
                    {
                        if (albumElement.HasElements && albumElement.Element("title").Value == e.AddedItems[0].ToString())
                        {
                            _albumId = albumElement.Element("album_id").Value;
                            GetAudioFilesFromAlbum();
                        }
                    }
                }
            }
        }

        private void AudioFilesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // т.к. данное событие срабатывает при ИЗМЕНЕНИИ состояния выбранности (не обязательно при конкретном выборе), то нужно
            // обрабатывать случай, когда в списке нет выбранного элемента
            if (e.AddedItems.Count == 0)
            {
                SetCurrentTrackNumber(0);
            }
            else if (fileStorage.FileExists("shared/transfers/playList.xml"))
            {
                using (IsolatedStorageFileStream isostream = fileStorage.OpenFile("shared/transfers/playList.xml", FileMode.Open))
                {
                    XDocument playList = XDocument.Load(isostream);
                    var playElements = playList.Root.Elements();
                    int i = 0;
                    
                    foreach (var playElement in playElements)
                    {
                        if (playElement.HasElements && ((playElement.Element("artist").Value + " - " + playElement.Element("title").Value) == e.AddedItems[0].ToString()))
                        {
                            StreamWriter fileWriter = new StreamWriter(new IsolatedStorageFileStream(
                                "currentTrackNumber.txt", FileMode.OpenOrCreate, fileStorage));
                            fileWriter.WriteLine(i);
                            fileWriter.Close();
                        }
                        i++;
                    }
                }
            }
            playButton_Click(null, null);
        }

        #endregion SELECTION CHANGED METHODS

        private void SetCurrentTrackNumber(int number)
        {
            try
            {
                StreamWriter fileWriter = new StreamWriter(new IsolatedStorageFileStream(
                    "currentTrackNumber.txt", FileMode.Create, fileStorage));
                fileWriter.WriteLine(number);
                fileWriter.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void positionSlider_Tap(object sender, GestureEventArgs e)
        {
            AudioTrack audioTrack = null;
            TimeSpan duration = TimeSpan.Zero;

            try
            {
                // Sometimes these property accesses will raise exceptions
                audioTrack = BackgroundAudioPlayer.Instance.Track;

                if (audioTrack != null)
                    duration = audioTrack.Duration;
                
                var ratio = Convert.ToDouble(e.GetPosition(positionSlider).X)/
                               Convert.ToDouble(positionSlider.ActualWidth);
               
                TimeSpan changedTimeSpan = new TimeSpan(Convert.ToInt64(duration.Ticks * ratio));
                
                BackgroundAudioPlayer.Instance.Position = changedTimeSpan;
            }
            catch
            {
            }

            if (audioTrack == null)
                return;       
        }

        private void SetRightIcons()
        {
            //Dictionary<string, string> options = GetPlayingOptions();
            Dictionary<string, string> options = Global.GetPlayingOptions();

            if (App.DarkVisibility == Visibility.Visible)
            {
                _btRepeat.UriSource = new Uri("Images/Icons/DARK.repeat.png", UriKind.Relative);
                _btShuffle.UriSource = new Uri("Images/Icons/DARK.shuffle.png", UriKind.Relative);
            }
            else
            {
                _btRepeat.UriSource = new Uri("Images/Icons/LIGHT.repeat.png", UriKind.Relative);
                _btShuffle.UriSource = new Uri("Images/Icons/LIGHT.shuffle.png", UriKind.Relative);
            }

            Regex regex = new Regex(@"([A-Z]+){4,5}");
            string newUriRepaet = options["isRepeatPlaying"] == "True"
                                ? regex.Replace(_btRepeat.UriSource.OriginalString, "GRAY")
                                : _btRepeat.UriSource.OriginalString;
            
            string newUriShuffle = options["isRandomPlaying"] == "True"
                         ? regex.Replace(_btShuffle.UriSource.OriginalString, "GRAY")
                         : _btShuffle.UriSource.OriginalString;

            _btRepeat.UriSource = new Uri(newUriRepaet, UriKind.Relative);
            _btShuffle.UriSource = new Uri(newUriShuffle, UriKind.Relative);

            repeatImg.Source = _btRepeat;
            shuffleImg.Source = _btShuffle;
        }

        private void repeatImg_Tap(object sender, GestureEventArgs e)
        {
            Dictionary<string, string> options = Global.GetPlayingOptions();
            options["isRepeatPlaying"] = options["isRepeatPlaying"] == "True" ? "False" : "True";
            ChangePlayingMode(options, "repeat");
            SetPlayingOptions(options);
            foreach (var option in options)
            {
                Debug.WriteLine(option);
            }
        }

        private void shuffleImg_Tap(object sender, GestureEventArgs e)
        {
            Dictionary<string, string> options = Global.GetPlayingOptions();
            options["isRandomPlaying"] = options["isRandomPlaying"] == "True" ? "False" : "True";
            ChangePlayingMode(options, "shuffle");
            SetPlayingOptions(options);
            foreach (var option in options)
            {
                Debug.WriteLine(option);
            }
        }

        private void SetPlayingOptions(Dictionary<string, string> options)
        {
            try
            {
                StreamWriter fileWriter = new StreamWriter(new IsolatedStorageFileStream(
                    "playingOptions.txt", FileMode.Create, fileStorage));
                fileWriter.WriteLine(options["isRepeatPlaying"]);
                fileWriter.WriteLine(options["isRandomPlaying"]);
                fileWriter.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void ChangePlayingMode(Dictionary<string, string> options, string typeAction)
        {
            Regex regex = new Regex(@"([A-Z]+){4,5}");
            switch (typeAction)
            {
                case "repeat":
                    if (options["isRepeatPlaying"] == "True" && options["isRandomPlaying"] == "True")
                    {
                        string newUriRepeat = regex.Replace(_btRepeat.UriSource.OriginalString, "GRAY");
                        _btRepeat.UriSource = new Uri(newUriRepeat, UriKind.Relative);
                        repeatImg.Source = _btRepeat;

                        string newUriShuffle = App.DarkVisibility == Visibility.Visible
                                     ? regex.Replace(_btShuffle.UriSource.OriginalString, "DARK")
                                     : regex.Replace(_btShuffle.UriSource.OriginalString, "LIGHT");
                        _btShuffle.UriSource = new Uri(newUriShuffle, UriKind.Relative);
                        shuffleImg.Source = _btShuffle;

                        options["isRandomPlaying"] = "False";
                    }
                    else
                    {
                        string newUriRepeat;
                        if (options["isRepeatPlaying"] == "True")
                        {
                            newUriRepeat = regex.Replace(_btRepeat.UriSource.OriginalString, "GRAY");
                        }
                        else
                        {
                            newUriRepeat = App.DarkVisibility == Visibility.Visible
                                     ? regex.Replace(_btRepeat.UriSource.OriginalString, "DARK")
                                     : regex.Replace(_btRepeat.UriSource.OriginalString, "LIGHT");
                        }
                        _btRepeat.UriSource = new Uri(newUriRepeat, UriKind.Relative);
                        repeatImg.Source = _btRepeat;
                    }
                    break;
                case "shuffle":
                    if (options["isRepeatPlaying"] == "True" && options["isRandomPlaying"] == "True")
                    {
                        string newUriShuffle = regex.Replace(_btShuffle.UriSource.OriginalString, "GRAY");
                        _btShuffle.UriSource = new Uri(newUriShuffle, UriKind.Relative);
                        repeatImg.Source = _btShuffle;

                        string newUriRepeat = App.DarkVisibility == Visibility.Visible
                                     ? regex.Replace(_btRepeat.UriSource.OriginalString, "DARK")
                                     : regex.Replace(_btRepeat.UriSource.OriginalString, "LIGHT");
                        _btRepeat.UriSource = new Uri(newUriRepeat, UriKind.Relative);
                        repeatImg.Source = _btRepeat;

                        options["isRepeatPlaying"] = "False";
                    }
                    else
                    {
                        string newUriShuffle;
                        if (options["isRandomPlaying"] == "True")
                        {
                            newUriShuffle = regex.Replace(_btShuffle.UriSource.OriginalString, "GRAY");
                        }
                        else
                        {
                            newUriShuffle = App.DarkVisibility == Visibility.Visible
                                     ? regex.Replace(_btShuffle.UriSource.OriginalString, "DARK")
                                     : regex.Replace(_btShuffle.UriSource.OriginalString, "LIGHT");
                        }
                        _btShuffle.UriSource = new Uri(newUriShuffle, UriKind.Relative);
                        shuffleImg.Source = _btShuffle;
                    }
                    break;
            }
        }
    }
}